/*
 * CoordExtractWithoutMarker.cpp
 * Created on: 04/04/2011
 * Author: catharine
 */

#include "ExtratorDeCamposSemMarcadores.h"

ExtratorDeCamposSemMarcadores::ExtratorDeCamposSemMarcadores() {
}

ExtratorDeCamposSemMarcadores::~ExtratorDeCamposSemMarcadores() {
}

Estrutura* ExtratorDeCamposSemMarcadores::encontrarCampos(IplImage* sum) {
    Estrutura* est = new Estrutura();
    int height = sum->height;
    int width = sum->width;

    double * sumLines1 = new double[height];
    ExtratorDeCamposSemMarcadores::sumLines(sum, sumLines1, height, width);
    Auxiliar::createArchieve("SomaDosElementosDaLinha.txt", sumLines1, height);

    const double lineDelta = Auxiliar::maxValue(sumLines1, height) * (0.20);

    double * sumLines2 = new double[height];
    findTableLines(sumLines1, sumLines2, height, lineDelta);
    Auxiliar::createArchieve("SomaDosElemntosDaLinhaComDelta.txt", sumLines2, height);

    //pair <middleLine, widthLine>
    Vector<pair<int, int> > lines;
    lines = findCoordinatesLines(sumLines2, height);

    /*********************************************************************/

    //colunas
    //soma dos elementos da coluna
    double * colLines1 = new double[width];
    sumColumns(sum, colLines1, height, width);
    Auxiliar::createArchieve("SomaDosElemntosDaColuna.txt", colLines1, width);

    const double columnDelta = Auxiliar::maxValue(colLines1, width) * (0.21);

    double * colLines2 = new double[width];
    //modifica os valores menores que delta para 0
    findTableLines(colLines1, colLines2, width, columnDelta);
    Auxiliar::createArchieve("SomaDosElemntosDaColunaComDelta.txt", colLines2, width);

    //pair <middleColumn, widthColumn>
    Vector<pair<int, int> > columns;
    columns = findCoordinatesLines(colLines2, width);

    vector<Campo*> campos = achaCamposAPartirDeLinhaEColuna(columns, lines);
    est->SetCampos(campos);
    delete (sumLines1);
    delete (sumLines2);
    delete (colLines1);
    delete (colLines2);
    return est;
}

vector<Campo*> ExtratorDeCamposSemMarcadores::achaCamposAPartirDeLinhaEColuna(Vector<pair<int, int> > columns,
        Vector<pair<int, int> > lines) {
    vector<Campo*> rects;
    Vector<pair<int, int> >::iterator itColumn = columns.begin();
    Vector<pair<int, int> >::iterator itLine = lines.begin();
    int delta = 5;

    while (itColumn != columns.end()) {
        itLine = lines.begin();
        while (itLine != lines.end()) {
            int x = (*itColumn).first + floor((*itColumn).second / 2) + delta;

            int y = (*itLine).first + floor((*itLine).second / 2) + delta;

            itLine++;
            int h = ((*itLine).first - floor((*itLine).second / 2) - y) - delta;

            itColumn++;
            int w = ((*itColumn).first - floor((*itColumn).second / 2) - x)
                    - delta;
            itColumn--;

            if (w > 0 && h > 0) {
                if (w > 20 && h > 21) {
                    Campo* campo = new Campo(x, y, w, h, BOOLEANO);
                    campo->SetTipo(BOOLEANO);
                    rects.push_back(campo);
                }
            }
        }
        itColumn++;
    }
    cout << "achou " << rects.size() << " rects" << endl;
    return rects;
}

/*
 * Sum the elements of picture lines.
 * @param image Image used to sum ​​the elements of line.
 * @param sumLines Array with values ​​of the sum of each line.
 */
void ExtratorDeCamposSemMarcadores::sumLines(IplImage * image, double * sumLines, int height, int width) {
    for (int i = 1; i < height; i++) {
        double s = 0;
        for (int j = 1; j < width; j++) {
            s += cvGetReal2D(image, i, j) + cvGetReal2D(image, i - 1, j - 1)
                    - cvGetReal2D(image, i, j - 1) - cvGetReal2D(image, i - 1,
                    j);
        }
        sumLines[i - 1] = s;
    }
}

/*
 * Sum the elements of picture columns.
 * @param image Image used to sum ​​the elements columns.
 * @param sumColumns Array with values ​​of the sum of each column.
 */
void ExtratorDeCamposSemMarcadores::sumColumns(IplImage * image, double * sumColumns, int height, int width) {
    for (int i = 1; i < width; i++) {
        double s = 0;
        for (int j = 1; j < height; j++) {
            s += cvGetReal2D(image, j, i) + cvGetReal2D(image, j - 1, i - 1)
                    - cvGetReal2D(image, j - 1, i) - cvGetReal2D(image, j, i
                    - 1);
        }
        sumColumns[i - 1] = s;
    }
}

/*
 * Find the lines in the table.
 * @param sumTableLines Sum of each image line.
 * @param sumDst Sum indicating the position of each line
 * @param sumTableLinesSize The size of sumTablesLines.
 * @param delta Value used to detect the line.
 */
void ExtratorDeCamposSemMarcadores::findTableLines(double * sumTableLines,
        double * sumDst, int sumTableLineSize, int delta) {
    for (int i = 0; i < sumTableLineSize; i++) {
        double value = sumTableLines[i];
        if (value < delta) {
            sumDst[i] = 0;
        } else {
            sumDst[i] = value;
        }
    }
}

/*
 * Find the coordinates of lines and columns.
 * @param sum
 * @param sumSize
 */
Vector<pair<int, int> > ExtratorDeCamposSemMarcadores::findCoordinatesLines(
        double * sum, int sumSize) {
    Vector<pair<int, int> > lines;
    bool isZero = false;
    int widthLine = 0;
    int initialLine = 0;
    int finalLine = 0;
    int middle = 0;

    for (int i = 0; i < sumSize; i++) {
        if (sum[i] == 0 && isZero == false) {
            isZero = true;
            initialLine = i;
        }

        if (sum[i] == 0 && isZero == true) {
            widthLine++;
        }

        if (sum[i] != 0 && isZero == true) {
            isZero = false;
            finalLine = i;

            middle = floor((initialLine + finalLine) / 2);
            pair<int, int> p(middle, widthLine);
            lines.push_back(p);

            widthLine = 0;
        }
    }
    return lines;
}